會特別寫這篇的原因是以前學習框架的時候只學語法而不懂原理,如果被問到使用框架有什麼好處可能也回答不太出來,由於React是透過Virtual DOM來提升網頁渲染的效率,所以今天要來探討Virtual DOM的運作原理,在了解Virtual DOM之前先來了解什麼是DOM吧!
DOM是什麼?
文件物件模型(Document Object Model, DOM)是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件(樹)的結構化表示法,並定義讓程式可以存取並改變文件架構、風格和內容的方法。(擷取MDN的部分說明
由下圖可以知道DOM是樹狀結構從document根結點向下延伸,下面依附了許多子節點
我們很常利用js來操作DOM,當瀏覽器在更新畫面的時候會觸發repaint(回流)以及reflow(重繪)這兩個更新機制
repaint
畫面元素更換樣式時候就觸發(background-color、color…)
reflow
更改畫面的佈局(結構排列)就會觸發(更改視窗大小,操作css屬性:position、width、height…)
頻繁操作DOM其實相當吃瀏覽器資源,導致效能低落,這就是為甚麼我們需要vitural DOM,要修改一個子節點就要重新繪製整個DOM 聽起來就很不智慧,所以就要借助Virtual DOM的演算法,就可以只更新需要異動的部分。
這是一般的html結構
<div id="header">
<h1 class="title">Apple</h1>
<p class="content">lemon</p>
</div>
這是Virtual DOM的結構,是JavaScript模擬出來的物件, 會以以下的格式儲存起來
{
tag: "div",
props: {
id: "header"
},
children: [
{
tag: "h1",
props: { className: "title" },
children: ["Apple"]
}, {
tag: "p",
props: { className: "content" },
children: ["lemon"]
}
]
}
下方就用程式碼來稍微模擬一下Virtual DOM的執行過程
var count = 0;
var tree = render(count);
var rootNode = createElement(tree);
document.body.appendChild(rootNode);
count++
var newTree = render(count);
var patches = diff(tree, newTree);
rootNode = patch(rootNode, patches);
tree = newTree;
什麼是patch?
patch指的是在原有的DOM結構上做異動
###關於diff演算法
傳統的diff演算法複雜度為O(n³) 處理100個節點就要進行100萬次的比對,Virtual DOM的diff演算法為O(n) 與傳統的差異在於下幾點:
以往如果是手動操作,每操作一次就會更新一次dom,如果是透過react setState就會是將多個操作合併為一次的操作,避免頻繁更新頁面,因此開發者只要專注在資料邏輯上,畫面的更新機制全部交給React處理即可。
參考資料
MDN
diff-algorithm-implemented-reactjs
很好的文章,virtual dom 說明得很清楚,不過 repaint 和 reflow 的說明是不是誤植相反了? XD
謝謝你的提醒 已更正XD
感謝清楚的解說,讓我更了解Virtual dom
不過下方的 replaint 拼錯了,應該是 repaint當瀏覽器在更新畫面的時候會觸發replaint(回流)以及reflow(重繪)這兩個更新機制
謝謝你的提醒
已修正!